package newclasses;

import java.util.Hashtable;
import java.util.Vector;

import src.RTPpacket;
import temp.TypeConverter;

public class RecoveryAlgorithm {

	private Hashtable<Integer,byte[]> packets;
	private int lastRead;
	private int bytesPerPacket;
	private int windowLengthInPackets;
	private int templateLengthInBytes;
	
	
	public RecoveryAlgorithm(int bytesPerPacket, int windowLengthInPackets,	int templateLengthInBytes) {
		super();
		lastRead = 0;
		packets = new Hashtable<Integer, byte[]>();
		this.bytesPerPacket = bytesPerPacket;
		this.windowLengthInPackets = windowLengthInPackets;
		this.templateLengthInBytes = templateLengthInBytes;
	}

	
	public Vector<Byte> add(RTPpacket packet){
		
		if (packet == null) {
			return recovery();
		}else{
					
			byte[] data = new byte[packet.getpayload_length()];
			packet.getpayload(data);
			Vector<Byte> temp = new Vector<Byte>(packet.getpayload_length());
			for (int i = 0; i < data.length; i++) {
				temp.add(data[i]);
			}
			
			packets.put(packet.getsequencenumber(),data);
			lastRead = packet.getsequencenumber();
			return temp;
		}
	}

	private Vector<Byte> recovery() {
		
		byte[] window = new byte[windowLengthInPackets* bytesPerPacket];
		int windowIndex = 0;
				
		for (int i = 1; i <= windowLengthInPackets; i++) {
			int currentPacket = lastRead -(windowLengthInPackets - i );
			if (packets.containsKey(currentPacket)) {
				byte[] current = packets.get(currentPacket);
				
				for (int j = 0; j < current.length; j++) {
					window[windowIndex++] = current[j];
				}
			}
		}
	
		
		byte[] template = new byte[templateLengthInBytes];
		

		int temp = windowIndex - 1;
		for (int i = 0; i < template.length; i++) {
			template[i] = window[temp - i];
		}
		
		
		
		return recovery(window,template,windowIndex);
	}

	private Vector<Byte> recovery(byte[] window, byte[] template,int windowLength) {
		
		Vector<Byte> newPacket = new Vector<Byte>(bytesPerPacket);
		
		short[] windowInShort = new short[windowLength - bytesPerPacket];
		short[] templateInShort = new short[template.length];
		
		
		for (int i = 0; i < windowInShort.length; i++) {
			windowInShort[i] = TypeConverter.byteSignedToUnsegned(window[i]);
		}
		 
		for (int i = 0; i < templateInShort.length; i++) {
			templateInShort[i] = TypeConverter.byteSignedToUnsegned(template[i]);
		}
		
		
		int bestFactorPosition = 0;
		double bestFactor = 0;
		
		
		// a janela menos o tamanho do tamplate
		int n = windowInShort.length - templateInShort.length;
		for (int i = 0; i < n; i++) {
			
			double temp = C(i,windowInShort,templateInShort);
			
			if (temp > bestFactor ) {
				bestFactorPosition = i;
				bestFactor = temp;
			}
			
		}
		
		for (int i = bestFactorPosition; i < bytesPerPacket; i++) {
			newPacket.add(window[i]);
		}
		return newPacket;
	}
	
	
	private double C(int n,short[] window,short[] template){

		int num = 0;
		int den = 0;
		
		for (int i = 0; i < template.length; i++) {
			num += window[n + i + 1 ] * template[i];
			den += window[n + i + 1 ] * window[n + i + 1 ];
		}
		
		if (den == 0) {
			return 1;
		}
		return num/den;
	}
	
}
